package data

import (
	"eag_arch_layout/internal/conf"
	"eag_arch_layout/internal/model/VO"
	"fmt"
	"github.com/go-kratos/kratos/v2/log"
	"strings"

	"gorm.io/driver/sqlserver"
	"gorm.io/gorm"
)

// BaseRepo .
type BaseRepo struct {
	// TODO wrapped database client
	db *gorm.DB
}

// NewBaseRepo .
func NewBaseRepo(c *conf.Data, logger log.Logger) (*BaseRepo, func(), error) {
	cleanup := func() {
		log.NewHelper(logger).Info("closing the b resources")
	}
	db, err := NewDB(c)
	if err != nil {
		log.NewHelper(logger).Info("connection db fail")
	}
	return &BaseRepo{
		db: db,
	}, cleanup, nil
}

func Pager[T interface{}](b BaseRepo, vSql string, whereSql []string, para []interface{}, searchModel *VO.PageSearchModel) ([]*T, int64) {
	var rows []*T
	whereSqlStr := strings.Join(whereSql, " AND ")
	if len(whereSqlStr) > 0 {
		whereSqlStr = " WHERE " + whereSqlStr
	}
	vSql1 := fmt.Sprintf("SELECT * FROM (%s) AS t %s", vSql, whereSqlStr)
	vSql1 = vSql1 + fmt.Sprintf(" order by %s OFFSET %d ROWS FETCH NEXT %d ROWS ONLY ", searchModel.Order, searchModel.Offset, searchModel.Limit)
	var allRows int //查询到的总记录数
	vSql2 := fmt.Sprintf("SELECT count(1) FROM (%s) AS t %s", vSql, whereSqlStr)
	if para == nil {
		b.db.Raw(vSql1).Scan(&rows)
		b.db.Raw(vSql2).Scan(&allRows)
	} else {
		b.db.Raw(vSql1, para...).Scan(&rows)
		b.db.Raw(vSql2, para...).Scan(&allRows)
	}
	return rows, int64(allRows)
}

func Pager4VxeTable[T interface{}](b BaseRepo, vSql string, whereSql []string, para []interface{}, searchModel *VO.PageSearchVxeModel) ([]*T, int64) {
	var rows []*T
	whereSqlStr := strings.Join(whereSql, " AND ")
	if len(whereSqlStr) > 0 {
		whereSqlStr = " WHERE " + whereSqlStr
	}
	vSql1 := fmt.Sprintf("SELECT * FROM (%s) AS t %s", vSql, whereSqlStr)
	vSql1 = vSql1 + fmt.Sprintf(" order by %s OFFSET %d ROWS FETCH NEXT %d ROWS ONLY ", searchModel.Order, searchModel.Offset, searchModel.Limit)
	var allRows int //查询到的总记录数
	vSql2 := fmt.Sprintf("SELECT count(1) FROM (%s) AS t %s", vSql, whereSqlStr)
	if para == nil {
		b.db.Raw(vSql1).Scan(&rows)
		b.db.Raw(vSql2).Scan(&allRows)
	} else {
		b.db.Raw(vSql1, para...).Scan(&rows)
		b.db.Raw(vSql2, para...).Scan(&allRows)
	}
	return rows, int64(allRows)
}

func CreateFilterWhereSql(clmFilters []*VO.ClmFilter) ([]string, []interface{}) {
	var whereSql []string
	var param []interface{}
	for _, filter := range clmFilters {
		if filter.Opt == "like" {

			whereSql = append(whereSql, fmt.Sprintf(" %s LIKE ? ", filter.Prop))
			param = append(param, fmt.Sprintf("%%%s%%", filter.Val))
		}
		if filter.Opt == "eq" {
			whereSql = append(whereSql, fmt.Sprintf(" %s = ? ", filter.Prop))
			param = append(param, filter.Val)
		}
	}
	return whereSql, param
}

func NewDB(c *conf.Data) (*gorm.DB, error) {
	// github.com/denisenkom/go-mssqldb
	dsn := c.Database.Dsn
	db, err := gorm.Open(sqlserver.Open(dsn), &gorm.Config{})
	return db, err
}
